﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Pg.BioMedics.SDR.Data;
using Pg.BioMedics.SDR.Entities;
using Pg.BioMedics.SDR.Entities.Codes;
using Pg.BioMedics.SDR.Caching;

namespace Pg.BioMedics.SDR.Data.Caching
{
    /// <summary>
    /// Provides data access routines for Document and related reoutines. This class uses 
    /// distributed cache as a source for some entities.
    /// </summary>
    internal sealed class CachedDocumentManager : DocumentManager
    {
        #region Constructors

        /// <summary>
        /// Creates an instance of CachedDocumentManager with data mapper strategy 
        /// initialization.
        /// </summary>
        /// <param name="dataMapperStrategy">Data mapper strategy utilized by this manager</param>
        internal CachedDocumentManager(IDataMapperStrategy dataMapperStrategy)
            : base(dataMapperStrategy) { }

        #endregion

        #region Overriden methods

        /// <summary>
        /// Inserts a new document into the database and distributed cache
        /// </summary>
        /// <param name="document">A new document</param>
        /// <returns>Saved document</returns>
        public override Document InsertDocument(Document document)
        {
            try
            {
                document = base.InsertDocument(document);
                SDRCacheContext.Instance.DocumentCache.Put(document);

                return document;
            }
            catch (Exception ex)
            {
                throw new DataCachingException("Couldnot insert document", ex);
            }
        }

        /// <summary>
        /// Gets document from the distributed cache. If document with given id does not 
        /// exist it returns null
        /// </summary>
        /// <param name="documentId">Document unique id</param>
        /// <returns>Document instance or null if doesnot exist</returns>
        public override Document GetDocumentById(int documentId)
        {
            try
            {
                return (from document in SDRCacheContext.Instance.DocumentCache.Query
                        where document.Id == documentId
                        select document).FirstOrDefault();
            }
            catch (Exception ex)
            {
                throw new DataCachingException("Couldnot get document by id {0}", ex, documentId);
            }
        }

        /// <summary>
        /// Sets given document status to the document entity stored both 
        /// in the database and in the distributed cache
        /// </summary>
        /// <param name="document">Document entity</param>
        /// <param name="statusCode">Document status code</param>
        /// <param name="author">Status change author</param>
        public override void SetDocumentStatus(Document document, string statusCode, Person author)
        {
            try
            {
                // update database definition
                base.SetDocumentStatus(document, statusCode, author);
                Document selectedDocument = base.GetDocumentById(document.Id.Value);

                // update cached definition
                SDRCacheContext.Instance.DocumentCache.Put(selectedDocument);
            }
            catch (Exception ex)
            {
                throw new DataCachingException("Couldnot set document status", ex);
            }
        }

        /// <summary>
        /// Gets list of documents in the given status
        /// </summary>
        /// <param name="statusCode">Document status code</param>
        /// <param name="statusAuthor">Document status author</param>
        /// <returns>List of documents</returns>
        public override IList<Document> GetDocumentsByStatus(string statusCode, Person statusAuthor)
        {
            try
            {
                return (from document in SDRCacheContext.Instance.DocumentCache.Query
                        where (document.StatusCode == statusCode) && (document.StatusAuthorLogin == statusAuthor.Login)
                        select document).ToList();
            }
            catch (Exception ex)
            {
                throw new DataCachingException("Couldnot get documents by status {0} and status author {1}", ex, statusCode, statusAuthor);
            }
        }

        /// <summary>
        /// Gets list of replaced documents by the given document
        /// </summary>
        /// <param name="document">Replacing document</param>
        /// <returns>List of documents replaced by the given document</returns>
        public override IList<Document> GetReplacedDocuments(Document document)
        {
            try
            {
                return (from doc in SDRCacheContext.Instance.DocumentCache.Query
                        where doc.Id == document.OriginalId
                        select doc).ToList();
            }
            catch (Exception ex)
            {
                throw new DataCachingException("Couldnot get replaced documents", ex);
            }
        }

        /// <summary>
        /// Gets all documents stored in the cache
        /// </summary>
        /// <returns>List of documents stored in the cache</returns>
        public override IList<Document> GetAllDocuments()
        {
            try
            {
                return (from document in SDRCacheContext.Instance.DocumentCache.Query
                        select document).ToList();
            }
            catch (Exception ex)
            {
                throw new DataCachingException("Couldnot get all documents", ex);
            }
        }

        #endregion
    }
}
